home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / amiga / gcctls92.lha / ar / archive.c < prev    next >
C/C++ Source or Header  |  1992-04-20  |  9KB  |  330 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Hugh Smith at The University of Guelph.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)archive.c    5.7 (Berkeley) 3/21/91";
  39. #endif /* not lint */
  40.  
  41. #include <sys/param.h>
  42. #include <sys/stat.h>
  43. #include <fcntl.h>
  44. #include <unistd.h>
  45. #include <errno.h>
  46. #include <dirent.h>
  47. #include <ar.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include "archive.h"
  52. #include "extern.h"
  53.  
  54. #ifdef DEBUG
  55. #define BADFMT() badfmt(__LINE__)
  56. #else
  57. #define BADFMT() badfmt()
  58. #endif
  59.  
  60. extern CHDR chdr;            /* converted header */
  61. extern char *archive;            /* archive name */
  62.  
  63. typedef struct ar_hdr HDR;
  64. static char hb[sizeof(HDR) + 1];    /* real header */
  65.  
  66. open_archive(mode)
  67.     int mode;
  68. {
  69.     int created, fd, nr;
  70.     char buf[SARMAG];
  71.     
  72.     created = 0;
  73.     if (mode & O_CREAT) {
  74.         mode |= O_EXCL;
  75.         if ((fd = open(archive, mode, DEFFILEMODE)) >= 0) {
  76.             /* POSIX.2 puts create message on stderr. */
  77.             if (!(options & AR_C))
  78.                 (void)fprintf(stderr,
  79.                     "ar: creating archive %s.\n", archive);
  80.             created = 1;
  81.             goto opened;
  82.         }
  83.         if (errno != EEXIST)
  84.             error(archive);
  85.         mode &= ~O_EXCL;
  86.     }
  87.     if ((fd = open(archive, mode, DEFFILEMODE)) < 0)
  88.         error(archive);
  89.  
  90.     /* 
  91.      * Attempt to place a lock on the opened file - if we get an 
  92.      * error then someone is already working on this library (or
  93.      * it's going across NFS).
  94.      */
  95. opened:    if (flock(fd, LOCK_EX|LOCK_NB) && errno != EOPNOTSUPP)
  96.         error(archive);
  97.     
  98.     /*
  99.      * If not created, O_RDONLY|O_RDWR indicates that it has to be
  100.      * in archive format.
  101.      */
  102.     if (!created &&
  103.         ((mode & O_ACCMODE) == O_RDONLY || (mode & O_ACCMODE) == O_RDWR)) {
  104.         if ((nr = read(fd, buf, SARMAG) != SARMAG)) {
  105.             if (nr >= 0)
  106.                 BADFMT();
  107.             error(archive);
  108.         } else if (bcmp(buf, ARMAG, SARMAG))
  109.             BADFMT();
  110.     } else if (write(fd, ARMAG, SARMAG) != SARMAG)
  111.         error(archive);
  112.     return(fd);
  113. }
  114.  
  115. void
  116. close_archive(fd)
  117.     int fd;
  118. {
  119.     (void)close(fd);            /* Implicit unlock. */
  120. }
  121.  
  122. /* Convert ar header field to an integer. */
  123. #define    AR_ATOI(from, to, len, base) { \
  124.     bcopy(from, buf, len); \
  125.     buf[len] = '\0'; \
  126.     to = strtol(buf, (char **)NULL, base); \
  127. }
  128.  
  129. /*
  130.  * get_arobj --
  131.  *    read the archive header for this member
  132.  */
  133. get_arobj(fd)
  134.     int fd;
  135. {
  136.     struct ar_hdr *hdr;
  137.     register int len, nr;
  138.     register char *p, buf[20];
  139.  
  140.     nr = read(fd, hb, sizeof(HDR));
  141.     if (nr != sizeof(HDR)) {
  142.         if (!nr)
  143.             return(0);
  144.         if (nr < 0)
  145.             error(archive);
  146.         BADFMT();
  147.     }
  148.  
  149.     hdr = (struct ar_hdr *)hb;
  150.     if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
  151.       {
  152. fprintf (stderr, "found string >%2.2s<\n", hdr->ar_fmag);
  153.         BADFMT();
  154.       }
  155.  
  156.     /* Convert the header into the internal format. */
  157. #define    DECIMAL    10
  158. #define    OCTAL     8
  159.  
  160.     AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), DECIMAL);
  161.     AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), DECIMAL);
  162.     AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), DECIMAL);
  163.     AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), OCTAL);
  164.     AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), DECIMAL);
  165.  
  166.     /* Leading spaces should never happen. */
  167.     if (hdr->ar_name[0] == ' ')
  168.         BADFMT();
  169.  
  170.     /*
  171.      * Long name support.  Set the "real" size of the file, and the
  172.      * long name flag/size.
  173.      */
  174.     if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) {
  175.         chdr.lname = len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1);
  176.         if (len <= 0 || len > MAXNAMLEN)
  177.             BADFMT();
  178.         nr = read(fd, chdr.name, len);
  179.         if (nr != len) {
  180.             if (nr < 0)
  181.                 error(archive);
  182.             BADFMT();
  183.         }
  184.         chdr.name[len] = 0;
  185.         chdr.size -= len;
  186.     } else {
  187.         chdr.lname = 0;
  188.         bcopy(hdr->ar_name, chdr.name, sizeof(hdr->ar_name));
  189.  
  190.         /* Strip trailing spaces, null terminate. */
  191.         for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
  192.         *++p = '\0';
  193.     }
  194.     return(1);
  195. }
  196.  
  197. static int already_written;
  198.  
  199. /*
  200.  * put_arobj --
  201.  *    Write an archive member to a file.
  202.  */
  203. put_arobj(cfp, sb)
  204.     CF *cfp;
  205.     struct stat *sb;
  206. {
  207.     register int lname;
  208.     register char *name;
  209.     struct ar_hdr *hdr;
  210.     off_t size;
  211.  
  212.     /*
  213.      * If passed an sb structure, reading a file from disk.  Get stat(2)
  214.      * information, build a name and construct a header.  (Files are named
  215.      * by their last component in the archive.)  If not, then just write
  216.      * the last header read.
  217.      */
  218.     if (sb) {
  219.         name = rname(cfp->rname);
  220.         (void)fstat(cfp->rfd, sb);
  221.  
  222.         /*
  223.          * If not truncating names and the name is too long or contains
  224.          * a space, use extended format 1.
  225.          */
  226.         lname = strlen(name);
  227.         if (options & AR_TR) {
  228.             if (lname > OLDARMAXNAME) {
  229.                 (void)fflush(stdout);
  230.                 (void)fprintf(stderr,
  231.                     "ar: warning: %s truncated to %.*s\n",
  232.                     name, OLDARMAXNAME, name);
  233.                 (void)fflush(stderr);
  234.             }
  235.             (void)sprintf(hb, HDR3, name, sb->st_mtime, sb->st_uid,
  236.                 sb->st_gid, sb->st_mode, sb->st_size, ARFMAG);
  237.             lname = 0;
  238.         } else if (lname > sizeof(hdr->ar_name) || index(name, ' '))
  239.             (void)sprintf(hb, HDR1, AR_EFMT1, lname, sb->st_mtime,
  240.                 sb->st_uid, sb->st_gid, sb->st_mode,
  241.                 sb->st_size + lname, ARFMAG);
  242.         else {
  243.             lname = 0;
  244.             (void)sprintf(hb, HDR2, name, sb->st_mtime, sb->st_uid,
  245.                 sb->st_gid, sb->st_mode, sb->st_size, ARFMAG);
  246.         }
  247.         size = sb->st_size;
  248.     } else {
  249.         lname = chdr.lname;
  250.         name = chdr.name;
  251.         size = chdr.size;
  252.     }
  253.  
  254.     if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR))
  255.         error(cfp->wname);
  256.     if (lname) {
  257.         if (write(cfp->wfd, name, lname) != lname)
  258.             error(cfp->wname);
  259.         already_written = lname;
  260.     }
  261.     copy_ar(cfp, size);
  262.     already_written = 0;
  263. }
  264.  
  265. /*
  266.  * copy_ar --
  267.  *    Copy size bytes from one file to another - taking care to handle the
  268.  *    extra byte (for odd size files) when reading archives and writing an
  269.  *    extra byte if necessary when adding files to archive.  The length of
  270.  *    the object is the long name plus the object itself; the variable
  271.  *    already_written gets set if a long name was written.
  272.  *
  273.  *    The padding is really unnecessary, and is almost certainly a remnant
  274.  *    of early archive formats where the header included binary data which
  275.  *    a PDP-11 required to start on an even byte boundary.  (Or, perhaps,
  276.  *    because 16-bit word addressed copies were faster?)  Anyhow, it should
  277.  *    have been ripped out long ago.
  278.  */
  279. copy_ar(cfp, size)
  280.     CF *cfp;
  281.     off_t size;
  282. {
  283.     static char pad = '\n';
  284.     register off_t sz;
  285.     register int from, nr, nw, off, to;
  286.     char buf[8*1024];
  287.     
  288.     if (!(sz = size))
  289.         return;
  290.  
  291.     from = cfp->rfd;
  292.     to = cfp->wfd;
  293.     sz = size;
  294.     while (sz && (nr = read(from, buf, MIN(sz, sizeof(buf)))) > 0) {
  295.         sz -= nr;
  296.         for (off = 0; off < nr; nr -= off, off += nw)
  297.             if ((nw = write(to, buf + off, nr)) < 0)
  298.                 error(cfp->wname);
  299.     }
  300.     if (sz) {
  301.         if (nr == 0)
  302.             BADFMT();
  303.         error(cfp->rname);
  304.     }
  305.  
  306.     if (cfp->flags & RPAD && size & 1 && (nr = read(from, buf, 1)) != 1) {
  307.         if (nr == 0)
  308.             BADFMT();
  309.         error(cfp->rname);
  310.     }
  311.     if (cfp->flags & WPAD && (size + already_written) & 1 &&
  312.         write(to, &pad, 1) != 1)
  313.         error(cfp->wname);
  314. }
  315.  
  316. /*
  317.  * skip_arobj -
  318.  *    Skip over an object -- taking care to skip the pad bytes.
  319.  */
  320. void
  321. skip_arobj(fd)
  322.     int fd;
  323. {
  324.     off_t len;
  325.  
  326.     len = chdr.size + (chdr.size + chdr.lname & 1);
  327.     if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
  328.         error(archive);
  329. }
  330.